//模拟执行栈

function first(){
    console.log('in first');
    second();
    console.log('out first')
}

function second(){
    console.log('in second');
}

first();

/**
 * 执行上下文和作用域链详解：
 * 
 * 1. 当程序启动时，开始执行全局代码时，全局执行上下文(Global Execution Context)会被创建并且压入执行栈(Execution Stack)中 -----所有执行的起点
 * 
 * 2. 代码执行到first()函数被调用时：
 *    - 创建first函数的执行上下文(Function Execution Context)
 *    - first执行上下文被压入执行栈顶部
 *    - 执行first函数内部代码
 * 
 * 3. 在first函数内部执行console.log('in first')后，遇到second()调用：
 *    - 创建second函数的执行上下文
 *    - second执行上下文被压入执行栈顶部
 *    - 执行second函数内部代码
 * 
 * 4. second函数执行完毕后：
 *    - second执行上下文从执行栈中弹出并销毁
 *    - 控制权返回给first函数
 *    - 继续执行first函数剩余代码console.log('out first')
 * 
 * 5. first函数执行完毕后：
 *    - first执行上下文从执行栈中弹出并销毁
 *    - 控制权返回给全局执行上下文
 * 
 * 6. 程序执行完毕，全局执行上下文最后被销毁
 * 
 * 执行栈变化过程：
 * 初始状态：     [Global EC]
 * 调用first：    [Global EC, first EC]
 * 调用second：   [Global EC, first EC, second EC]
 * second完成：   [Global EC, first EC]
 * first完成：    [Global EC]
 * 程序结束：     []
 * 
 * 输出结果：
 * in first
 * in second
 * out first
 */

// 更复杂的作用域链示例
function outerFunction(x) {
    var outerVar = x;
    
    function innerFunction(y) {
        var innerVar = y;
        console.log(outerVar + innerVar); // 可以访问外层作用域的变量
    }
    
    return innerFunction;
}

var closure = outerFunction(10);
closure(5); // 输出: 15

/**
 * 详细执行步骤分析：
 * 
 * === 第一阶段：全局代码执行 ===
 * 1. 创建全局执行上下文(Global EC)并压入执行栈
 * 2. 全局词法环境创建：
 *    - 环境记录：{ outerFunction: function, closure: undefined }
 *    - 外部环境引用：null (全局环境没有外部环境)
 * 3. 函数声明outerFunction被提升并存储在全局环境记录中
 * 
 * === 第二阶段：执行 var closure = outerFunction(10) ===
 * 4. 调用outerFunction(10)：
 *    - 创建outerFunction执行上下文并压入执行栈
 *    - 创建outerFunction的词法环境：
 *      * 环境记录：{ x: 10, outerVar: undefined, innerFunction: function }
 *      * 外部环境引用：指向全局词法环境
 * 
 * 5. 执行outerFunction内部代码：
 *    - var outerVar = x; → outerVar被赋值为10
 *    - innerFunction函数声明被提升
 *    - 环境记录更新：{ x: 10, outerVar: 10, innerFunction: function }
 * 
 * 6. return innerFunction：
 *    - 返回innerFunction函数对象
 *    - 关键：innerFunction携带了对outerFunction词法环境的引用！
 *    - outerFunction执行上下文从执行栈弹出
 *    - 但是！outerFunction的词法环境不会被销毁，因为被innerFunction引用
 * 
 * 7. closure变量被赋值为返回的innerFunction
 * 
 * === 第三阶段：执行 closure(5) ===
 * 8. 调用closure(5)，实际上是调用innerFunction(5)：
 *    - 创建innerFunction执行上下文并压入执行栈
 *    - 创建innerFunction的词法环境：
 *      * 环境记录：{ y: 5, innerVar: undefined }
 *      * 外部环境引用：指向outerFunction的词法环境！(闭包的关键)
 * 
 * 9. 执行innerFunction内部代码：
 *    - var innerVar = y; → innerVar被赋值为5
 *    - 环境记录更新：{ y: 5, innerVar: 5 }
 * 
 * 10. 执行console.log(outerVar + innerVar)：
 *     - 查找outerVar：
 *       * 在当前环境记录中查找 → 未找到
 *       * 沿作用域链向上查找 → 在outerFunction词法环境中找到outerVar: 10
 *     - 查找innerVar：
 *       * 在当前环境记录中查找 → 找到innerVar: 5
 *     - 计算：10 + 5 = 15
 *     - 输出：15
 * 
 * 11. innerFunction执行完毕：
 *     - innerFunction执行上下文从执行栈弹出并销毁
 *     - 控制权返回给全局执行上下文
 * 
 * === 执行栈和词法环境变化过程 ===
 * 
 * 初始状态：
 * 执行栈: [Global EC]
 * 词法环境: Global LE { outerFunction: func, closure: undefined }
 * 
 * 调用outerFunction(10)：
 * 执行栈: [Global EC, outerFunction EC]
 * 词法环境: 
 *   - Global LE { outerFunction: func, closure: undefined }
 *   - outerFunction LE { x: 10, outerVar: 10, innerFunction: func } → 外部引用: Global LE
 * 
 * outerFunction返回后：
 * 执行栈: [Global EC]
 * 词法环境: 
 *   - Global LE { outerFunction: func, closure: innerFunction }
 *   - outerFunction LE { x: 10, outerVar: 10, innerFunction: func } → 仍然存在！被closure引用
 * 
 * 调用closure(5)：
 * 执行栈: [Global EC, innerFunction EC]
 * 词法环境:
 *   - Global LE { outerFunction: func, closure: innerFunction }
 *   - outerFunction LE { x: 10, outerVar: 10, innerFunction: func }
 *   - innerFunction LE { y: 5, innerVar: 5 } → 外部引用: outerFunction LE
 * 
 * === 闭包的本质 ===
 * 闭包 = 函数 + 该函数被创建时的词法环境
 * 
 * 在这个例子中：
 * - innerFunction就是闭包函数
 * - 它"记住"了创建时的词法环境(outerFunction的词法环境)
 * - 即使outerFunction执行完毕，innerFunction仍能访问outerVar
 * - 这就是闭包的"记忆"能力
 */



/**
 * 作用域链(Scope Chain)解释：
 * 
 * 1. 每个执行上下文都有一个词法环境(Lexical Environment)
 * 2. 词法环境包含：
 *    - 环境记录(Environment Record)：存储变量和函数声明
 *    - 外部环境引用(Outer Environment Reference)：指向外层词法环境
 * 
 * 3. 作用域链就是通过外部环境引用形成的链式结构
 * 4. 变量查找过程：
 *    - 首先在当前词法环境中查找
 *    - 如果找不到，沿着作用域链向上查找
 *    - 直到全局词法环境，如果还找不到则报ReferenceError
 * 
 * 5. 闭包的形成：
 *    - innerFunction执行时，其词法环境的外部引用指向outerFunction的词法环境
 *    - 即使outerFunction执行完毕，其词法环境仍被innerFunction引用而不会被垃圾回收
 *    - 这就形成了闭包，innerFunction可以访问outerVar
 */